package cn.cloud9.opencloud.common.security;

import cn.cloud9.opencloud.common.util.EmptyUtil;
import cn.cloud9.opencloud.common.util.EncodeUtil;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * @author OnCloud9
 * @description
 * @project Open-Cloud
 * @date 2022年04月16日 17:56
 */
public class XssConfigFilter implements Filter {

    private Logger _logger = LoggerFactory.getLogger(getClass());

    public static final String IGNORE_PROPERTIES = "ignoreProperties";
    public static String[] ignoreProperties = null;
    public static final String EXCLUDE_URLS = "excludeUrls";
    public static String[] excludeUrls = null;

    @Override
    public void init(FilterConfig filterConfig) {
        final String ignorePropertiesConfig = filterConfig.getInitParameter(IGNORE_PROPERTIES);
        final String excludeUrlsConfig = filterConfig.getInitParameter(EXCLUDE_URLS);
        // 存在配置参数则装载参数
        if (!EmptyUtil.isEmptyString(ignorePropertiesConfig)) ignoreProperties = ignorePropertiesConfig.split(",");
        if (!EmptyUtil.isEmptyString(excludeUrlsConfig)) excludeUrls = excludeUrlsConfig.split(",");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 需要判断是否是需要忽略的请求地址
        final String servletPath = request.getServletPath();

        // 前面只处理不是需要忽略的请求
        boolean isEmptyUrls = EmptyUtil.isEmptyArray(excludeUrls);
        boolean isEmptyPath = EmptyUtil.isEmptyString(servletPath);
        boolean isSafePath = false;
        if(!isEmptyPath && !isEmptyUrls) isSafePath = Arrays.stream(excludeUrls).anyMatch(servletPath::contains);

        // 如果不是需要忽略的路径
        if (!isSafePath) {
            // 取出请求体
            final ServletInputStream inputStream = request.getInputStream();
            final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024 * 2];
            int cursor = inputStream.read(buffer);
            while (cursor > 0) {
                outputStream.write(buffer, 0, cursor);
                cursor = inputStream.read(buffer);
            }
            String requestBodyString = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);

            // 包装成XSS请求。。。
            if (!EmptyUtil.isEmptyString(requestBodyString)) {
                final JSONObject jsonObject = JSONObject.parseObject(requestBodyString);
                EncodeUtil.encodeJsonObject(jsonObject, ignoreProperties);
                requestBodyString = jsonObject.toJSONString();
            }
            request = new XssRequestWrapper(request, requestBodyString);

        }

        // 最后是放行
        filterChain.doFilter(request, response);
    }
}
